package gl.java.umsp;

import gl.java.umsp.bean.Match;
import gl.java.umsp.bean.MatchResult;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;

/**
 * 代号 G 网关<br>
 * 代号 B 业务服务器<br>
 * 代号 C 客户端<br>
 * 业务相关操作
 *
 * @author geliang
 */
public class Umsp {
    /**
     * 堵塞队列超时时间
     */
    public static final int TIME_BLOCK_POP = 1;

    private static HashMap<Integer, String> CmdHashMap = new HashMap<Integer, String>();

    public static String CmdToString(int cmd) {
        return CmdHashMap.get(cmd);
    }

    /**
     * 心跳
     */
    public static final int CMD_HEARTBEAT = 520;

    static {
        CmdHashMap.put(CMD_HEARTBEAT, "CMD_HEARTBEAT");
    }

    /**
     * 用户登录
     */
    public static final int CMD_LOGIN = 1;

    static {
        CmdHashMap.put(CMD_LOGIN, "CMD_LOGIN");
    }

    /**
     * 用户登录response
     */
    public static final int CMD_LOGIN_RSP = 2;

    static {
        CmdHashMap.put(CMD_LOGIN_RSP, "CMD_LOGIN_RSP");
    }

    /**
     * 用户登出
     */
    public static final int CMD_LOGOUT = 3;

    static {
        CmdHashMap.put(CMD_LOGOUT, "CMD_LOGOUT");
    }

    /**
     * 用户登出response
     */
    public static final int CMD_LOGOUT_RSP = 4;

    static {
        CmdHashMap.put(CMD_LOGOUT_RSP, "CMD_LOGOUT_RSP");
    }

    /**
     * 客户端发送消息
     */
    public static final int CMD_MSG = 5;

    static {
        CmdHashMap.put(CMD_MSG, "CMD_MSG");
    }

    /**
     * 客户端发送消息response
     */
    public static final int CMD_MSG_RSP = 6;

    static {
        CmdHashMap.put(CMD_MSG_RSP, "CMD_MSG_RSP");
    }


    public static final int CMD_ROOM_SERVICE_LOGIN = 7;

    static {
        CmdHashMap.put(CMD_ROOM_SERVICE_LOGIN, "CMD_ROOM_SERVICE_LOGIN");
    }

    public static final int CMD_ROOM_SERVICE_LOGIN_RSP = 8;

    static {
        CmdHashMap.put(CMD_ROOM_SERVICE_LOGIN_RSP, "CMD_ROOM_SERVICE_LOGIN_RSP");
    }

    public static final int CMD_MATCH = 9;

    static {
        CmdHashMap.put(CMD_MATCH, "CMD_MATCH");
    }

    public static final int CMD_MATCH_RSP = 10;

    static {
        CmdHashMap.put(CMD_MATCH_RSP, "CMD_MATCH_RSP");
    }

    public static final int CMD_ROOM_ENTER = 11;

    static {
        CmdHashMap.put(CMD_ROOM_ENTER, "CMD_ROOM_ENTER");
    }

    public static final int CMD_ROOM_EXIT = 12;

    static {
        CmdHashMap.put(CMD_ROOM_EXIT, "CMD_ROOM_EXIT");
    }

    public static final int CMD_ROOM_USER_CHANGED = 13;

    static {
        CmdHashMap.put(CMD_ROOM_USER_CHANGED, "CMD_ROOM_USER_CHANGED");
    }


    /**
     * 错误消息
     */
    public static final int CMD_ERR = 999;

    static {
        CmdHashMap.put(CMD_ERR, "CMD_ERR");
    }

    /**
     * 消息订阅
     */
    public static final int CMD_SUBSCRIBE = 1000;

    static {
        CmdHashMap.put(CMD_SUBSCRIBE, "CMD_SUBSCRIBE");
    }

    /**
     * 消息发布
     */
    public static final int CMD_PUBLISH = 1001;

    static {
        CmdHashMap.put(CMD_PUBLISH, "CMD_PUBLISH");
    }

    private static final int LEN_TOKEN = 32;
    private static final int LEN_ID = 4;

    private static Logger logger = LoggerFactory.getLogger(Umsp.class);


    private static GenericFutureListener<Future<? super Void>> listener = new GenericFutureListener<Future<? super Void>>() {

        @Override
        public void operationComplete(Future<? super Void> future)
                throws Exception {
            if (!future.isSuccess()) {
                logger.info("send fail:" + future.cause());
            }
        }
    };

    private static void send(final int cmd, final Channel toCtx,
                             final ByteBuf buf) {

        ChannelFuture future = toCtx.write(buf); // (3)
        future.addListener(listener);
        toCtx.flush();

    }

    // 错误包常量化

    public static void returnErrMsg(final int cmd, int errCode, String errMsg,
                                    final Channel toCtx) {
        UmspHeader uf = new UmspHeader(cmd, errCode, errMsg.getBytes());
        writeAndFlush(toCtx, uf);
        logger.warn("[MSG-SERR]:[code:" + errCode + "][" + errMsg + "]");
    }
    public static void returnErrMsg(final int cmd, ErrCode errCode,
                                    final Channel toCtx) {
        UmspHeader uf = new UmspHeader(cmd, errCode);
        writeAndFlush(toCtx, uf);
        logger.warn("[MSG-SERR]:[code:" + errCode );
    }

    public static void returnStringMsg(final int cmd, String msg, final Channel toCtx) {
        UmspHeader uf = new UmspHeader(cmd, msg.getBytes());
        writeAndFlush(toCtx, uf);
        logger.debug("[MSG-String] " + toCtx.remoteAddress() + " [cmd:" + Umsp.CmdToString(cmd) + "][" + msg + "]");
    }

    public static UmspHeader createStringMsg(final int cmd, String msg) {
        return new UmspHeader(cmd, msg.getBytes());
    }

    public static void returnBoradcastStringMsg(final int cmd, final MatchResult result, String msg, final Channel toCtx) {
        UmspHeader uf = new UmspHeader(cmd, result, msg.getBytes());
        writeAndFlush(toCtx, uf);
        logger.debug("[MSG-String] " + toCtx.remoteAddress() + " [cmd:" + cmd + "][" + msg + "]");
    }

    public static void returnMsg(UmspHeader header, Channel toCtx) {
        logger.debug("[MSG-Binary]:" + header);
        writeAndFlush(toCtx, header);
    }

    // 心跳包常量化
    private static UmspHeader HeartBeat;

    static {
        HeartBeat = new UmspHeader(CMD_HEARTBEAT);
    }

    public static void returnHeart(Channel toCtx) {
        writeAndFlush(toCtx, HeartBeat);
    }

    public static void returnEmpty(Channel toCtx, int cmd) {
        UmspHeader msg = new UmspHeader(cmd);
        writeAndFlush(toCtx, msg);
    }

    public static void writeAndFlush(Channel toCtx, UmspHeader msg) {
        if (toCtx == null || msg == null) {
            return;
        }
        ChannelFuture future = toCtx.writeAndFlush(
                (toCtx.attr(UmspConfig.WebSocketBin).get() != null
                        && toCtx.attr(UmspConfig.WebSocketBin).get() > 0)
                        ? new BinaryWebSocketFrame(msg.toBytBuf())
                        : msg.toBytBufNoLength());
        future.addListener(listener);
    }

    public static void returnLogin(Channel toCtx, int gameID, int userID, String token) {
        UmspHeader msg = new UmspHeader(Umsp.CMD_LOGIN, token.getBytes());
        msg.userID = userID;
        msg.gameID = gameID;
        writeAndFlush(toCtx, msg);
    }

    public static void returnMatch(Channel toCtx, Match match) {
        UmspHeader msg = new UmspHeader(Umsp.CMD_MATCH, match.toString().getBytes());
        writeAndFlush(toCtx, msg);
    }


//	/**
//	 * 解析登录消息,返回用户信息
//	 *
//	 * @param msg
//	 * @return
//	 */
//	public static UserInfo parseLoginMsg(GWFrame msg, ChannelHandlerContext ctx) {
//		if (msg == null || msg.frameData.length == 0
//				|| (msg.frameData.length != LEN_TOKEN + LEN_ID)) {
//			return null;
//		}
//		try {
//			UserInfo mUserInfo = new UserInfo();
//			mUserInfo.channel = ctx.channel();
//			mUserInfo.gameID = msg.header.gameID;
//			mUserInfo.serviceID = msg.header.serviceID;
//
//			ByteBuffer buffer = ByteBuffer.wrap(msg.frameData);
//			buffer.order(ByteOrder.LITTLE_ENDIAN);
//			mUserInfo.ID = buffer.getInt();
//			byte[] token = new byte[LEN_TOKEN];
//			buffer.get(token);
//			mUserInfo.token = token;
//			return mUserInfo;
//		} catch (BufferUnderflowException e) {
//			e.printStackTrace();
//		}
//
//		return null;
//	}
//
//	/**
//	 * 解析用户的ID
//	 *
//	 * @param body
//	 *            消息数据
//	 * @return
//	 */
//	public static int parseUserIdInMsg(byte[] body) {
//		if (body == null || body.length == 0 || (body.length < LEN_ID)) {
//			logger.info("body==null||body.length==0||(body.length<LEN_ID)");
//			return USERID_NOTEXIST;
//		}
//		try {
//			ByteBuffer buffer = ByteBuffer.wrap(body);
//			buffer.order(ByteOrder.LITTLE_ENDIAN);
//			return buffer.getInt();
//		} catch (BufferUnderflowException e) {
//			e.printStackTrace();
//		}
//
//		return USERID_NOTEXIST;
//	}
//
//	/**
//	 * 通知业务服务器用户登录
//	 *
//	 * @param fromCtx
//	 * @param toCtx
//	 * @param serviceID
//	 */
//	public static void noticeRaceSerUserLogin(Channel fromCtx, Channel toCtx,
//			int serviceID) {
//		ByteBuffer buffer = ByteBuffer.allocate(4);
//		buffer.order(ByteOrder.LITTLE_ENDIAN);
//		buffer.putInt(serviceID);
//		GWFrame uf = new GWFrame(Umsp.CMD_G_B_USERLOGIN, buffer.array());
//
//		ByteBuf buf;
//		buf = toCtx.alloc().buffer(4); // (1)
//		buf.writeBytes(uf.getHeaderClipLength());
//		buf.writeBytes(uf.getBody());
//		send(Umsp.CMD_G_B_USERLOGIN, toCtx, buf);
//	}
//
//	/**
//	 * 通知业务服务器用户掉线或退出
//	 *
//	 * @param fromCtx
//	 * @param toCtx
//	 * @param userID
//	 */
//	public static void noticeRaceSerUserLogout(Channel fromCtx, Channel toCtx,
//			int userID) {
//		ByteBuffer buffer = ByteBuffer.allocate(4);
//		buffer.order(ByteOrder.LITTLE_ENDIAN);
//		buffer.putInt(userID);
//		GWFrame uf = new GWFrame(Umsp.CMD_G_B_USERLOGOUT, buffer.array());
//
//		ByteBuf buf;
//		buf = toCtx.alloc().buffer(4); // (1)
//		buf.writeBytes(uf.getHeaderClipLength());
//		buf.writeBytes(uf.getBody());
//		send(Umsp.CMD_G_B_USERLOGOUT, toCtx, buf);
//	}
//
//	/**
//	 * 获取业务服务器连接
//	 *
//	 * @param serviceID
//	 *
//	 * @return
//	 */
//	public static Channel getRaceSerConnection(int serviceID) {
//		Channel key = ServerConnectionPool.getInstance()
//				.getConnectionChannel(serviceID);
//		if (key != null) {
//			return key;
//		}
////		logger.info("race server is not login");
//		return null;
//	}
//
//	/**
//	 * 发送消息给目标
//	 *
//	 * @param ctx
//	 * @param msg
//	 */
//	public static void sendMsgToTargetUser(Channel ctx, GWFrame msg) {
//		if (msg == null || msg.getBody() == null) {
//			logger.info("the msg is null");
//			return;
//		}
//		int userID = Umsp.parseUserIdInMsg(msg.getBody());
//		if (userID == USERID_NOTEXIST) {
//			logger.info("the target userID  of msg is ill");
//			return;
//		}
//		Channel toCtx2 = UserConnectionPool.getInstance().getConnectionChannel(userID);
//		if (toCtx2 == null) {
//			logger.info("Donot find the user connection");
//			return;
//		}
//		if (toCtx2 != null) {
//			Umsp.frowardMsg(Umsp.CMD_G_C_USERMSG, ctx, toCtx2,
//					msg);
//		}
//	}
//
//	/**
//	 * 发送消息给目标
//	 *
//	 * @param ctx
//	 * @param msg
//	 */
//	public static void sendMsgToTargetUser(int cmd, Channel ctx, int userID,
//			byte[] data) {
//		if (data == null) {
//			logger.info("the msg is null");
//			return;
//		}
//		Channel toCtx2 = UserConnectionPool.getInstance().getConnectionChannel(
//				userID);
//		if (toCtx2 == null) {
//			logger.info("Donot find the user connection");
//			return;
//		}
//		if (toCtx2 != null) {
//			Umsp.frowardMsg(cmd, ctx, toCtx2, data);
//		}
//	}
//
//	/**
//	 * 发送消息给目标
//	 *
//	 * @param ctx
//	 * @param msg
//	 */
//	public static void sendMsgToTargetUser(int cmd, Channel ctx, int gameID,
//			int userID, byte[] data) {
//		if (data == null) {
//			logger.info("the msg is null");
//			return;
//		}
//		Channel toCtx2 = UserConnectionPool.getInstance().getConnectionChannel(
//				userID);
//		if (toCtx2 == null) {
//			logger.info("Donot find the user connection");
//			return;
//		}
//		if (toCtx2 != null) {
//			Umsp.frowardMsg(cmd, ctx, gameID, toCtx2, userID, data);
//		}
//	}
//
//	public static void sendMsgToALL(Channel fromChannel, GWFrame msg) {
//		if (msg == null || msg.getBody() == null) {
//			logger.info("the msg is null");
//			return;
//		}
//		Set<Channel> allChannelSet = UserConnectionPool.getInstance()
//				.getAllChannel();
//		if (allChannelSet != null) {
//			for (Channel channel : allChannelSet) {
//				Umsp.frowardMsg(Umsp.CMD_MSG_SEND_SINGLE,
//						fromChannel, channel, msg);
//			}
//		} else {
//			logger.info("UserConnectionPool allChannelSet is null.");
//		}
//
//		Set<Channel> allChannelSet1 = ServerConnectionPool.getInstance()
//				.getAllChannel();
//		if (allChannelSet1 != null) {
//			for (Channel channel : allChannelSet1) {
//				Umsp.frowardMsg(Umsp.CMD_MSG_SEND_SINGLE,
//						fromChannel, channel, msg);
//			}
//		} else {
//			logger.info("ServerConnectionPool allChannelSet is null.");
//		}
//
//	}
//
//	/**
//	 * 加入群组
//	 *
//	 * @param roomID
//	 *            群组ID
//	 * @param userID
//	 *            用户ID
//	 * @return
//	 * @throws JSONException
//	 */
//	public static Group handlejoinGroup(Channel channle, int roomID,
//			int userID, int flag) throws JSONException {
//
//		UserInfo userinfo = (UserInfo) UserConnectionPool.getInstance()
//				.getUserInfo(userID);
//		if (userinfo == null) {
//			logger.debug("userID" + userID
//					+ "is found(is login?),but he want join room " + roomID);
//			return null;
//		}
//		// if (userinfo.roomID!=Group.ROOM_ID_NOTEXIST) {
//		if (userinfo.roomID != roomID) {
//			// 用户身处另一个房间.则踢掉他
//			logger.debug("userID" + userID + "is exist in" + userinfo.roomID
//					+ "" + ",let he go away ");
//			handleLeaveGroup(channle, userinfo.roomID, userinfo.ID);
//		} else {
//			// 用户多次加入同一个房间
//			logger.debug("userID" + userID + "is exist in" + roomID
//					+ ",ignore this joinGroup request,return errcode");
//			Umsp.returnErrMsg(Umsp.CMD_ERR,
//					Umsp.ERRCODE_ROOM_JOIN_SAME, channle, channle);
//			return null;
//		}
//		// }
//		Group group = GroupManager.getInstance()
//				.joinGroup(roomID, userID, flag);
//		if (group != null) {
//			userinfo.roomID = roomID;
//			Umsp.returnNullMsg(Umsp.CMD_GROUP_JOIN_OK, channle,
//					channle);
//			Umsp.broadcastGroupUserState(channle, roomID);
//			Umsp.broadcastGroupUserJoin(channle, roomID, userID);
//
//		} else {
//
//			Umsp.returnErrMsg(Umsp.CMD_ERR,
//					Umsp.ERRCODE_NOTEXISTROOM, channle, channle);
//		}
//		return group;
//	}
//
//	public static Group handleLeaveGroup(Channel channle, int roomID, int userID)
//			throws JSONException {
//		final Group leaveGroup = GroupManager.getInstance().leaveGroup(roomID,
//				userID);
//		if (leaveGroup != null) {
//			logger.info("userID" + userID + "leave room " + roomID);
//			Umsp.returnNullMsg(Umsp.CMD_GROUP_LEAVE_OK, channle,
//					channle);
//			Umsp.broadcastGroupUserState(channle, roomID);
//			Umsp.broadcastGroupUserLeave(channle, roomID, userID);
//			GWChannelHandler.clearUserRoomState(channle);
//		} else {
//			logger.info("userID" + userID + "want to leave no exist room "
//					+ roomID);
//			Umsp.returnErrMsg(Umsp.CMD_ERR,
//					Umsp.ERRCODE_NOTEXISTROOM, channle, channle);
//		}
//		return leaveGroup;
//	}
//
//	/**
//	 * 在群组中广播消息
//	 *
//	 * @param fromChannel
//	 *            消息发送者连接
//	 * @param userID
//	 *            消息发送者ID
//	 * @param roomID
//	 *            广播目标房间ID
//	 * @param data
//	 *            数据
//	 * @return
//	 * @throws UnsupportedEncodingException
//	 */
//	public static boolean sendMsgToGroup(Channel fromChannel, int userID,
//			int roomID, byte[] data) throws UnsupportedEncodingException {
//		logger.info("datalength:" + data.length + "->"
//				+ new String(data, "UTF-8"));
//		Group group = GroupManager.getInstance().findGroup(roomID);
//		if (group == null) {
//			logger.warn("group is not be find ->ID:" + roomID);
//			return false;
//		} else {
//			for (int i = 0; i < group.groupUserIdList.size(); i++) {
//				final int toUserID = group.groupUserIdList.get(i);
//				if (userID != toUserID) {
//					sendMsgToTargetUser(CMD_MSG_SEND_GROUP, fromChannel,
//							userID, toUserID, data);
//				}
//			}
//			return true;
//		}
//	}
//
//	/**
//	 * 房间内广播成员状态
//	 *
//	 * @param fromChannel
//	 * @param roomID
//	 */
//	public static void broadcastGroupUserState(Channel fromChannel, int roomID) {
//		Group group = GroupManager.getInstance().findGroup(roomID);
//		if (group == null) {
//			logger.warn("broadcastGroupUserState fail,group is not be find");
//		} else {
//			for (int i = 0; i < group.groupUserIdList.size(); i++) {
//				final int toUserID = group.groupUserIdList.get(i);
//				sendMsgToTargetUser(CMD_GROUP_USER_STATE, fromChannel,
//						toUserID, group.toJSONString().getBytes());
//			}
//		}
//	}
//
//	public static void broadcastGroupUserJoin(Channel fromChannel, int roomID,
//			int userID) throws JSONException {
//		Group group = GroupManager.getInstance().findGroup(roomID);
//		if (group == null) {
//			logger.warn("broadcastGroupUserJoin fail,group is not be find");
//		} else {
//			for (int i = 0; i < group.groupUserIdList.size(); i++) {
//				final int toUserID = group.groupUserIdList.get(i);
//				sendMsgToTargetUser(CMD_GROUP_USER_JOIN, fromChannel, toUserID,
//						new JSONObject().put("userID", userID).toString()
//								.getBytes());
//			}
//		}
//	}
//
//	public static void broadcastGroupUserLeave(Channel fromChannel, int roomID,
//			int userID) throws JSONException {
//		Group group = GroupManager.getInstance().findGroup(roomID);
//		if (group == null) {
//			logger.warn("broadcastGroupUserLeave fail,group is not be find");
//		} else {
//			for (int i = 0; i < group.groupUserIdList.size(); i++) {
//				final int toUserID = group.groupUserIdList.get(i);
//				sendMsgToTargetUser(CMD_GROUP_USER_LEAVE, fromChannel,
//						toUserID, new JSONObject().put("userID", userID)
//								.toString().getBytes());
//			}
//		}
//	}
}
